package com.gqr.threadobjectclasscommonmethods;

/**
 * Copyright (C), 2020-2024,gqr
 * FileName:WaitNotifyPrintOddEvenWait
 * author:guqingrong
 * Date:2024-04-23 21:49
 * Description:两个线程交替打印0~100的奇偶数,用wait和notify
 * History:
 * <author>    <time>    <version>    <desc>
 * 作者姓名     修改时间     版本号        描述
 */
public class WaitNotifyPrintOddEvenWait {
    // 1. 一旦拿到锁,我们就打印
    // 2. 打印完,唤醒其他线程,自己就休眠
    private static int count=0;
    private static final Object lock = new Object();

    public static void main(String[] args) {
        new Thread(new TurningRunner(),"偶数").start();
        new Thread(new TurningRunner(),"奇数").start();
    }

    static class TurningRunner implements Runnable{
        /*
        * 1. 假设偶数线程先执行 虽然先start不一定先执行
        * 2. 偶数线程进入到同步代码块 拿到lock这个对象的锁 此时lock是被偶数线程所持有 打印出count等于0 然后count++
        * 3. 偶数线程调用lock.notify方法 此时系统会在当前挂起等待在wait方法出的多个线程中 随机找一个唤醒,被唤醒的线程会等待直到它拿到对象锁并继续执行
        * 3.1 偶数线程调用lock.notify 但是此时没有其他线程处于等待 没有唤醒其他线程
        * 3.2 任务没有结束 此时偶数线程调用wait 偶数线程交出锁 并挂起等待
        * 4. 奇数线程此时获取到锁 打印出count等于1 然后count++
        * 5.1 奇数线程调用lock.notify方法,此时系统会在当前挂起等待在wait方法处的多个线程中(其实就是偶数线程正在处于挂起),唤醒偶数线程,偶数线程会等待知道它拿到对象锁并继续执行
        * 5.2 任务没有结束,此时奇数线程调用wait ,奇数线程交出锁 并挂起等待
        * 6 偶数线程由于被唤醒了一直等待其他线程交出锁, 偶数线程获取到锁 进入同步代码 打印出count 循环往复
        *
        * */

        @Override
        public void run() {
            while (count<=100){
                synchronized (lock){
                    // 拿到锁就打印
                    System.out.println(Thread.currentThread().getName()+":"+count);
                    count++;
                    lock.notify();
                    if(count<=100){
                        try {
                            // 如果任务还没结束,就让出当前的锁,并休眠
                            lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}
